package com.wgchao.amc.service.impl;

import com.wgchao.amc.autho.AuthoInfoCenter;
import com.wgchao.amc.common.EvaluateInfo;
import com.wgchao.amc.common.PageData;
import com.wgchao.amc.common.ResultCommon;
import com.wgchao.amc.entity.base.SysBaseAgency;
import com.wgchao.amc.entity.base.SysBaseGr;
import com.wgchao.amc.entity.base.SysBaseGroup;
import com.wgchao.amc.entity.base.SysBaseRole;
import com.wgchao.amc.mapstruct.dto.SysBaseAgencyDTO;
import com.wgchao.amc.mapstruct.dto.SysBaseGroupDTO;
import com.wgchao.amc.mapstruct.dto.SysBaseRoleDTO;
import com.wgchao.amc.mapstruct.mapper.expand.SysBaseGroupMapperExpand;
import com.wgchao.amc.repository.base.SysBaseAgencyRepository;
import com.wgchao.amc.repository.base.SysBaseGrRepository;
import com.wgchao.amc.repository.base.SysBaseGroupRepository;
import com.wgchao.amc.repository.base.SysBaseRoleRepository;
import com.wgchao.amc.service.GroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @作者：wgchao
 * @时间：19:14 2019/10/19 0019
 * @用途：部门信息管理
 **/
@Service
@Transactional
public class GroupServiceImpl implements GroupService {
    @Autowired
    private SysBaseAgencyRepository agencyRepository;
    @Autowired
    private SysBaseGroupRepository groupRepository;
    @Autowired
    private SysBaseGroupMapperExpand groupMapperExpand;
    @Autowired
    private SysBaseGrRepository grRepository;
    @Autowired
    private SysBaseRoleRepository roleRepository;

    /**
     * 新增部门
     * @param groupDTO 部门信息
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseGroupDTO> save(SysBaseGroupDTO groupDTO, AuthoInfoCenter authoInfoCenter) throws Exception {
        //数据检校
        String error = null;
        if(!StringUtils.isEmpty(error = agencyCanUse(groupDTO.getAgencyCode()))) {
            return ResultCommon.fail(error);
        }
        if(groupDTO.getParGroup() != null){
            if((error = parGroupCanUse(groupDTO.getParGroup())) != null){
                return ResultCommon.fail(error);
            }
        }

        //开始保存
        SysBaseGroup group = groupMapperExpand.toEntity(groupDTO);
        group.setDel(false);
        group.setCreateTime(new Date());
        group.setCreateUser(authoInfoCenter.getUserId());
        group = groupRepository.save(group);

        groupDTO = groupMapperExpand.toDTO(group);
        groupDTO = groupMapperExpand.getAgencyInfo(groupDTO);
        groupDTO = groupMapperExpand.getParGroup(groupDTO);
        return ResultCommon.success().setData(groupDTO);
    }

    /**
     * 根据部门ID查询部门详情
     * @param groupId 部门ID
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(readOnly = true)
    public ResultCommon<SysBaseGroupDTO> search(Long groupId) throws Exception {
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            return ResultCommon.fail("部门不存在");
        }

        SysBaseGroupDTO groupDTO = groupMapperExpand.toDTO(groupOptional.get());
        groupDTO = groupMapperExpand.getAgencyInfo(groupDTO);
        groupDTO = groupMapperExpand.getParGroup(groupDTO);
        groupDTO = groupMapperExpand.getChildGroups(groupDTO);
        groupDTO = groupMapperExpand.getRoleInfos(groupDTO);
        return ResultCommon.success().setData(groupDTO);
    }

    /**
     * 查询机构下的部门列表
     * @param agencyCode 机构编号
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<List<SysBaseGroupDTO>> search(String agencyCode) throws Exception {
        Optional<SysBaseAgency> agencyOptional = agencyRepository.findById(agencyCode);
        if(!agencyOptional.isPresent()){
            return ResultCommon.fail("机构不存在");
        }
        SysBaseAgency agency = agencyOptional.get();
        if(agency.isCancel()){
            return ResultCommon.fail("机构已删除");
        }
        if(agency.isDel()){
            return ResultCommon.fail("机构已注销");
        }

        List<SysBaseGroup> groupList = groupRepository.findAllByAgencyCodeAndDelIsFalse(agencyCode);
        List<SysBaseGroupDTO> groupDTOS = groupList.stream().map(sysBaseGroup -> {
            SysBaseGroupDTO groupDTO = groupMapperExpand.toDTO(sysBaseGroup);
            groupDTO = groupMapperExpand.getCURDUserInfo(groupDTO);
            return groupDTO;
        }).collect(Collectors.toList());
        return ResultCommon.success().setData(groupDTOS);
    }

    /**
     * 分页查询部门信息
     * @param page 页码
     * @param limit 数据条数
     * @param groupId 部门ID
     * @param groupName 部门名称
     * @param child 是否查询子机构
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(readOnly = true)
    public ResultCommon<PageData<SysBaseGroupDTO>> page(int page, int limit, String agencyCode, Long groupId,
                                                         String groupName, boolean child) throws Exception {
        Specification<SysBaseGroup> specification = new Specification<SysBaseGroup>() {
            @Override
            public Predicate toPredicate(Root<SysBaseGroup> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicateList = new ArrayList<>();
                if(!StringUtils.isEmpty(agencyCode)){
                    Predicate predicate = criteriaBuilder.equal(root.get("agencyCode"), agencyCode);
                    predicateList.add(predicate);
                }
                if(groupId != null){
                    Predicate predicate = criteriaBuilder.equal(root.get("groupId"), groupId);
                    predicateList.add(predicate);
                }
                if(!StringUtils.isEmpty(groupName)){
                    Predicate predicate = criteriaBuilder.like(root.get("groupName"), groupName+"%");
                    predicateList.add(predicate);
                }
                Predicate predicate = criteriaBuilder.isFalse(root.get("del"));
                predicateList.add(predicate);
                Predicate[] predicates = new Predicate[predicateList.size()];
                return criteriaBuilder.and(predicateList.toArray(predicates));
            }
        };

        Pageable pageable = PageRequest.of(page-1, limit, Sort.by(Sort.Order.asc("groupId")));

        Page<SysBaseGroup> groupPage = groupRepository.findAll(specification, pageable);
        List<SysBaseGroupDTO> groupDTOS = groupPage.get().map(sysBaseGroup -> {
            SysBaseGroupDTO groupDTO = groupMapperExpand.toDTO(sysBaseGroup);
            groupDTO = groupMapperExpand.getAgencyInfo(groupDTO);
            groupDTO = groupMapperExpand.getParGroup(groupDTO);
            groupDTO = groupMapperExpand.getCURDUserInfo(groupDTO);
//            if(child){
//                groupDTO = groupMapperExpand.getChildGroups(groupDTO);
//            }
            return groupDTO;
        }).collect(Collectors.toList());

        return ResultCommon.success().setData(new PageData<SysBaseGroupDTO>(page, limit,
                Long.valueOf(groupPage.getTotalElements()).intValue(), groupDTOS));
    }

    /**
     * 更新部门信息
     * @param groupDTO 部门信息
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseAgencyDTO> update(SysBaseGroupDTO groupDTO, AuthoInfoCenter authoInfoCenter) throws Exception {
        String error = null;
        if((error = groupCanUse(groupDTO.getGroupId())) != null){
            return ResultCommon.fail(error);
        }
        if((error = agencyCanUse(groupDTO.getAgencyCode())) != null){
            return ResultCommon.fail(error);
        }
        if((error = parGroupCanUse(groupDTO.getParGroup())) != null){
            return ResultCommon.fail(error);
        }

        SysBaseGroup group = groupMapperExpand.toEntity(groupDTO);
        group.setLastUpdateTime(new Date());
        group.setLastUpdateUser(authoInfoCenter.getUserId());
        group = groupRepository.save(group);

        groupDTO = groupMapperExpand.toDTO(group);
        groupDTO = groupMapperExpand.getAgencyInfo(groupDTO);
        groupDTO = groupMapperExpand.getParGroup(groupDTO);
        return ResultCommon.success().setData(groupDTO);
    }

    /**
     * 删除部门信息（同时删除子部门）
     * @param groupIds 部门Id列表
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon deletes(List<Long> groupIds, AuthoInfoCenter authoInfoCenter) throws Exception {
        for(Long groupId : groupIds) {
            Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
            if(!groupOptional.isPresent()){
                throw new Exception(groupId+"部门不存在");
            }
            SysBaseGroup group = groupOptional.get();
            group.setDel(true);
            group.setDelUser(authoInfoCenter.getUserId());
            group.setDelTime(new Date());
            group = groupRepository.save(group);
            if(!deleteChilds(group.getGroupId(), authoInfoCenter)){
                throw new Exception("删除子部门失败");
            }
        }
        return ResultCommon.success();
    }

    private boolean deleteChilds(Long groupId, AuthoInfoCenter authoInfoCenter) throws Exception{
        List<SysBaseGroup> childs = groupRepository.findAllByParGroup(groupId);
        if(childs != null){
            for(SysBaseGroup child : childs){
                if(!child.isDel()){
                    child.setDel(true);
                    child.setDelTime(new Date());
                    child.setDelUser(authoInfoCenter.getUserId());
                    child = groupRepository.save(child);
                    if(!deleteChilds(child.getGroupId(), authoInfoCenter)){
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 根据部门ID查询部门以及下级部门列表
     * @param groupId 部门ID
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(readOnly = true)
    public ResultCommon<List<SysBaseGroupDTO>> searchChilds(Long groupId) throws Exception {
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            throw new Exception(groupId+"部门不存在");
        }
        SysBaseGroup group = groupOptional.get();
        List<SysBaseGroupDTO> groupDTOS = new ArrayList<>();
        groupDTOS.add(groupMapperExpand.toDTO(group));
        groupDTOS.addAll(childGroups(groupId));

        return ResultCommon.success().setData(groupDTOS);
    }

    /**
     * 根据部门ID查询部门以及下级部门列表(树状)
     * @param groupId 部门ID
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(readOnly = true)
    public ResultCommon<SysBaseGroupDTO> searchChildsTree(Long groupId) throws Exception {
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            throw new Exception(groupId+"部门不存在");
        }
        SysBaseGroup group = groupOptional.get();

        SysBaseGroupDTO groupDTO = groupMapperExpand.toDTO(group);
        groupDTO = groupMapperExpand.getChildGroups(groupDTO);
        return ResultCommon.success().setData(groupDTO);
    }

    private List<SysBaseGroupDTO> childGroups(Long groupId){
        List<SysBaseGroup> childs = groupRepository.findAllByParGroupAndDelIsFalse(groupId);
        List<SysBaseGroupDTO> childDTOs = new ArrayList<>();
        if(childs!=null && !childs.isEmpty()){
            for(SysBaseGroup child : childs){
                SysBaseGroupDTO childDTO = groupMapperExpand.toDTO(child);
                childDTOs.add(childDTO);
                List<SysBaseGroupDTO> cchilds = childGroups(childDTO.getGroupId());
                childDTOs.addAll(cchilds);
            }
        }
        return childDTOs;
    }

    /**
     * 为部门分配角色
     * @param groupId 部门ID
     * @param roleDTOs 角色列表
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseGroupDTO> assignedRoles(Long groupId, List<SysBaseRoleDTO> roleDTOs) throws Exception {
        //数据检校
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            return ResultCommon.fail("部门不存在");
        }
        SysBaseGroup group = groupOptional.get();
        if(group.isDel()){
            return ResultCommon.fail("部门已删除");
        }

        //删除原有的关系
        grRepository.cancelByGroupId(groupId, new Date());

        for(SysBaseRoleDTO roleDTO:roleDTOs){
            Optional<SysBaseRole> roleOptional = roleRepository.findById(roleDTO.getId());
            if(!roleOptional.isPresent()){
                throw new Exception(roleDTO.getId()+"角色不存在");
            }
            SysBaseRole role = roleOptional.get();
            if(role.isDel()){
                throw new Exception(roleDTO.getId()+"角色已删除");
            }
            SysBaseGr gr = grRepository.findFirstByRoleIdAndGroupId(role.getId(), groupId);
            if(gr == null){
                gr = new SysBaseGr();
                gr.setGroupId(groupId);
                gr.setRoleId(role.getId());
                gr.setCreateTime(new Date());
            }
            gr.setDel(false);
            gr.setDelTime(null);
            gr = grRepository.save(gr);
        }

        SysBaseGroupDTO groupDTO = groupMapperExpand.toDTO(group);
        groupDTO = groupMapperExpand.getRoleInfos(groupDTO);
        return ResultCommon.success().setData(groupDTO);
    }

    /**
     * 所属机构合法性检校
     * @param agencyCode
     * @return
     */
    private String agencyCanUse(String agencyCode) {
        Optional<SysBaseAgency> agencyOptional = agencyRepository.findById(agencyCode);
        if(!agencyOptional.isPresent()){
            return "所属机构不存在";
        }
        SysBaseAgency agency = agencyOptional.get();
        if(agency.isCancel()){
            return "所属机构已注销";
        }
        if(agency.isDel()){
            return "所属机构已删除";
        }
        return null;
    }

    /**
     * 部门合法性检校
     * @param groupId
     * @return
     */
    private String groupCanUse(Long groupId) {
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            return "部门不存在";
        }
        SysBaseGroup group = groupOptional.get();
        if(group.isDel()){
            return "部门已删除";
        }
        return null;
    }

    /**
     * 上级部门合法性检校
     * @param groupId
     * @return
     */
    private String parGroupCanUse(Long groupId) {
        if(groupId == null){
            return null;
        }
        Optional<SysBaseGroup> groupOptional = groupRepository.findById(groupId);
        if(!groupOptional.isPresent()){
            return "上级部门不存在";
        }
        SysBaseGroup group = groupOptional.get();
        if(group.isDel()){
            return "上级部门已删除";
        }
        return null;
    }
}
